package cn.yhbk.web.modules.manager.Service.Impl;
import java.time.LocalDateTime;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.yhbk.web.common.Util.ExcelUtil;
import cn.yhbk.web.common.Util.MyUtil;
import cn.yhbk.web.common.exception.ApiException;
import cn.yhbk.web.modules.manager.Mapper.TbCollegeMapper;
import cn.yhbk.web.modules.manager.Mapper.TbScholarShipTypeMapper;
import cn.yhbk.web.modules.manager.Mapper.TbStudentMapper;
import cn.yhbk.web.modules.manager.Pojo.DTO.Apply.ApplyDto;
import cn.yhbk.web.modules.manager.Pojo.DTO.Apply.ApplyExcelDto;

import cn.yhbk.web.modules.manager.Pojo.DTO.Apply.TbApplyDto;
import cn.yhbk.web.modules.manager.Pojo.DTO.Apply.TbApplyDto;
import cn.yhbk.web.modules.manager.Pojo.DTO.Gpa.GpaDto;
import cn.yhbk.web.modules.manager.Pojo.DTO.ScholarShip.ScholarShipDto;
import cn.yhbk.web.modules.manager.Pojo.Entity.*;
import cn.yhbk.web.modules.manager.Mapper.TbApplyMapper;
import cn.yhbk.web.modules.manager.Pojo.VO.Apply.ApplyPag;
import cn.yhbk.web.modules.manager.Pojo.VO.Apply.ApplyResp;
import cn.yhbk.web.modules.manager.Pojo.VO.OrderResponse;
import cn.yhbk.web.modules.manager.Service.*;
import cn.yhbk.web.modules.ums.mapper.UmsAdminRoleRelationMapper;
import cn.yhbk.web.modules.ums.mapper.UmsRoleMapper;
import cn.yhbk.web.modules.ums.model.UmsAdminRoleRelation;
import cn.yhbk.web.modules.ums.model.UmsRole;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 奖学金申请表 服务实现类
 * </p>
 *
 * @author 有何不可
 * @since 2023-08-05
 */
@Service
public class TbApplyServiceImpl extends ServiceImpl<TbApplyMapper, TbApply> implements ITbApplyService {

    @Autowired
    private UmsAdminRoleRelationMapper umsRoleResourceRelationMapper;

    @Autowired
    private UmsRoleMapper umsRoleMapper;

    @Autowired
    private TbApplyMapper tbApplyMapper;

    @Autowired
    private TbStudentMapper tbStudentMapper;

    @Autowired
    private ITbStudentService studentService;

    @Autowired
    private TbCollegeMapper tbCollegeMapper;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private ITbGpaRecordService gpaRecordService;

    @Autowired
    private ITbScholarshipService scholarshipService;

    @Autowired
    private TbScholarShipTypeMapper tbScholarShipTypeMapper;

    @Autowired
    @Lazy
    private IBursaryRecordService bursaryRecordService;

    @Autowired
    private ITbClassService classService;

    @Autowired
    private IOrderResultItemService itemService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public TbApplyDto getApplyById(Long id) {
        return tbApplyMapper.queryApplyById(id);
    }

    @Override
    public Boolean insertApply(TbApply tbApply) {
        return tbApplyMapper.insertApply(tbApply);
    }

    @Override
    public Boolean updateApplyById(TbApply tbApply) {
        return  tbApplyMapper.updateApplyById(tbApply);
    }

    @Override
    public Boolean deleteApplyById(Long id) {
        return tbApplyMapper.deleteApplyById(id);
    }

    @Override
    public ApplyPag getApplyInfoPag(Integer currentPage, Integer pageSize, Long typeId, Long scholarshipId,
                                    String year, Long jobNumber, Long majorId, Integer status) {
        // 获取账号
        Long adminPersonId = MyUtil.getCurrentAdminId();
        // 获取学院ID
        QueryWrapper<TbCollege> tbCollegeQueryWrapper = new QueryWrapper<>();
        tbCollegeQueryWrapper.eq("stu_work_office_id", adminPersonId);
        TbCollege tbCollege = tbCollegeMapper.selectOne(tbCollegeQueryWrapper);
        Long collegeId = tbCollege.getId();
        // 查询数据
        ApplyPag<TbApplyDto> applyPag = new ApplyPag();
        applyPag.setPageSize(pageSize);
        applyPag.setCurrentPage(currentPage);
        applyPag.setTotalPage(tbApplyMapper.queryManagerApplyNum(typeId, scholarshipId, year, jobNumber, collegeId, majorId, status));
        applyPag.setApplyList(tbApplyMapper.queryManagerApplyPage((currentPage - 1) * pageSize, pageSize, typeId, scholarshipId, year, jobNumber, collegeId, majorId, status));
        return applyPag;
    }

    @Override
    public Boolean acceptApply(Long applyId, Integer status) {
        Long adminPersonId = MyUtil.getCurrentAdminId();
        // 获取身份
        QueryWrapper<UmsAdminRoleRelation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("admin_id", adminPersonId);
        UmsAdminRoleRelation one = umsRoleResourceRelationMapper.selectOne(queryWrapper);
        // 判断身份
        TbApply tbApply = tbApplyMapper.selectById(applyId);
        Long roleId = one.getRoleId();
        UmsRole umsRole = umsRoleMapper.selectById(roleId);
        if(!umsRole.getName().equals("学工办")){
            throw new ApiException("身份不正确");
        }
        // 判断是同意还是不同意
        if(status == 1){
            tbApply.setStatus(2);
            // 加入奖学金记录表
            ((ITbApplyService)AopContext.currentProxy()).saveScholarshipRecord(tbApply);
        }
        else if (status == 0){
            tbApply.setStatus(0);
        }
        else{
            throw new ApiException("无效参数");
        }
        return tbApplyMapper.updateById(tbApply) == 1;
    }

    @Override
    public void saveScholarshipRecord(TbApply tbApply) {
        // 查询学生绩点信息
        TbStudent student = studentService.getById(tbApply.getStuId());
        // 查询奖学金信息
        TbScholarship scholarship = scholarshipService.getById(tbApply.getId());
        BursaryRecord bursaryRecord = new BursaryRecord();
        bursaryRecord.setBursaryName(scholarship.getName());
        bursaryRecord.setStuName(student.getName());
        bursaryRecord.setStuDescription(tbApply.getClassDesc());
        bursaryRecord.setGpaSum(tbApply.getGpaSum());
        bursaryRecord.setStuNumber(student.getJobNumber().toString());
        bursaryRecord.setBursaryId(tbApply.getScholarshipId());
        bursaryRecord.setCreateTime(LocalDateTime.now());
        bursaryRecord.setUpdateTime(LocalDateTime.now());
        bursaryRecord.setYear(tbApply.getYear());

        bursaryRecordService.save(bursaryRecord);
    }

    @Override
    public Boolean removeApply(Long applyId) {
        // 查询用户
        Long adminPersonId = MyUtil.getCurrentAdminId();
        QueryWrapper<TbStudent> wrapper = new QueryWrapper<>();
        wrapper.eq("admin_id", adminPersonId);
        TbStudent tbStudent = tbStudentMapper.selectOne(wrapper);
        Long stuId = tbStudent.getId();
        // 删除
        TbApply tbApply = this.baseMapper.selectById(applyId);
        QueryWrapper<TbApply> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", applyId);
        queryWrapper.eq("stu_id", stuId);

        // 删除缓存
        redisTemplate.delete("applyScholarshipEnd:" + stuId + "-" + tbApply.getScholarshipId() + '-' + tbApply.getYear());
        return tbApplyMapper.delete(queryWrapper) == 1;
    }

    @Override
    public ApplyPag getStuApplyInfoPag(Integer currentPage, Integer pageSize, Long typeId, Long scholarshipId, String year, Integer status) {
        // 查询学生
        Long adminId = MyUtil.getCurrentAdminId();
        TbStudent student = studentService.getStudentByAdminId(adminId);
        // 查询分页
        ApplyPag<ApplyDto> applyPag = new ApplyPag();
        applyPag.setPageSize(pageSize);
        applyPag.setCurrentPage(currentPage);
        applyPag.setApplyList(tbApplyMapper.queryApplyList((currentPage - 1) * pageSize, pageSize, student.getId(), year, scholarshipId, status, typeId));
        applyPag.setTotalPage(tbApplyMapper.queryApplyNum(student.getId(), year, scholarshipId, status, typeId));
//        applyPag.setTotalPage(tbApplyMapper.queryTotalNum(name, typeId, scholarshipId, year, student.getJobNumber(), student.getId(), null, null, status));
//        applyPag.setApplyList(tbApplyMapper.queryClassPage((currentPage - 1) * pageSize, pageSize, name, typeId, scholarshipId, year, student.getJobNumber(), student.getId(), null, null, status));
        return applyPag;
    }

    @Override
    public void getApplyExcel(String name, Long typeId, Long scholarshipId, String year, Long jobNumber, Long majorId, Integer status) {
        List<ApplyExcelDto> applyExcelDtoList = tbApplyMapper.queryApplyExcel(name, typeId, scholarshipId, year, jobNumber, majorId, status);
        try {
            ExcelUtil.outputExcel(response, applyExcelDtoList, ApplyExcelDto.class, "奖学金申请");
        } catch (IOException e){
            throw new ApiException(e.toString());
        }
    }

    @Override
    public Boolean apply(TbStudent student, TbClass tbClass, Long scholarshipId) {
        Long stuId = student.getId();
        LocalDateTime now = LocalDateTime.now();
        String year = String.valueOf(now.getYear());
        // 查询用户是否已经申请
        Integer count = this.baseMapper.countIsApply(stuId, year, scholarshipId);
        if (count > 0){
            throw new ApiException("请勿重复申请该奖学金");
        }

        // 查询是否挂科
        TbGpaRecord gpaRecord = gpaRecordService.getOne(new LambdaQueryWrapper<TbGpaRecord>().eq(TbGpaRecord::getStuId, stuId));
        if (!gpaRecord.getPass()){
            throw new ApiException("挂科无法申请奖学金");
        }


//        String getStr = (String) redisTemplate.opsForValue().get("applyScholarshipEnd:" + stuId + "-" + scholarshipId + '-' + year);
//        if (getStr != null){
//            throw new ApiException("请勿重复申请该奖学金");
//        }
//        // 判断是否满足申请奖学金
//        String str = (String) redisTemplate.opsForValue().get("gpaSort:" + majorId + "-" + scholarshipId + "-" + gradeId);
//        if (str == null){
//            throw new ApiException("错误，请联系管理员");
//        }
//        List<GpaDto> gpaDtoList = JSONUtil.toList(str, GpaDto.class);
//        List<GpaDto> collect = gpaDtoList.stream().filter(item -> item.getStuId().equals(stuId)).collect(Collectors.toList());
//
//        if (collect.size() == 0){
//            return false;
//        }

        // 保存申请
        TbApply tbApply = new TbApply();
        tbApply.setCreateTime(now);
        tbApply.setUpdateTime(now);
        tbApply.setStuId(stuId);
        tbApply.setNotes("");
        tbApply.setScholarshipId(scholarshipId);
        tbApply.setRefuse("");
        tbApply.setYear(year);
        tbApply.setGpaSum(gpaRecord.getGpaSum());
        tbApply.setClassDesc(tbClass.getDescription());
        tbApply.setJobNumber(student.getJobNumber().toString());


//        redisTemplate.opsForValue().set("applyScholarshipEnd:" + stuId + "-" + scholarshipId + '-' + year, "1");

        this.baseMapper.insert(tbApply);

        return true;
    }

//    @Override
//    public List<ScholarShipDto> getStuQualification(Long stuId) {
//        // 先检查缓存
//        String stuScholarshipStr = redisTemplate.opsForValue().get("stuScholarship:" + stuId);
//        if (stuScholarshipStr != null){
//            return JSONUtil.toList(stuScholarshipStr, ScholarShipDto.class);
//        }
//
//        List<ScholarShipDto> res = new ArrayList<>();
//        List<GpaDto> gpaRecordSort = gpaRecordService.getGpaRecordSort(stuId);
//        // 找到学生的排名
//        int stuNum = 1;
//        for (GpaDto gpaDto : gpaRecordSort) {
//            if (gpaDto.getStuId().equals(stuId)){
//                break;
//            }
//            stuNum ++;
//        }
//        // 学生排名比例
//        Double stuPro = stuNum * 1.0 / gpaRecordSort.size() * 100;
//
//        // TODO 获取所有奖学金类别
////        List<TbScholarShipType> tbScholarShipTypes = tbScholarShipTypeMapper.selectList(new QueryWrapper<>());
////        Map<Long, String> collect = tbScholarShipTypes.stream().collect(Collectors.toMap(TbScholarShipType::getId, TbScholarShipType::getName));
////        List<TbScholarship> scholarshipList = scholarshipService.list();
////        for (TbScholarship scholarship : scholarshipList) {
////            String proportion = scholarship.getProportion();
////            if (scholarship.getProportion() > stuPro){
////                res.add(new ScholarShipDto(scholarship.getName(), collect.get(scholarship.getTypeId()), scholarship.getProportion()));
////            }
////        }
//
//        redisTemplate.opsForValue().set("stuScholarship:" + stuId, JSONUtil.toJsonStr(res), 5, TimeUnit.HOURS);
//
//        return res;
//    }


    @Override
    public List<ApplyResp> getOrderSort(Long resultId, Long scholarshipId) {
        List<Long> stuList = getStuList(resultId);
        if(stuList.isEmpty())return new ArrayList<>();
        LambdaQueryWrapper<TbApply> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbApply::getScholarshipId, scholarshipId);
        queryWrapper.in(TbApply::getStuId, stuList);
        queryWrapper.eq(TbApply::getYear, LocalDateTime.now().getYear());
        queryWrapper.orderByDesc(TbApply::getGpaSum);
        List<TbApply> tbApplies = this.baseMapper.selectList(queryWrapper);
        return BeanUtil.copyToList(tbApplies, ApplyResp.class);
    }

    @Override
    public List<OrderResponse> getOrderSortResponse(Long resultId, Long scholarshipId) {
        List<Long> stuList = getStuList(resultId);
        LambdaQueryWrapper<TbApply> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbApply::getScholarshipId, scholarshipId);
        queryWrapper.in(TbApply::getStuId, stuList);
        queryWrapper.eq(TbApply::getYear, LocalDateTime.now().getYear());
        queryWrapper.orderByDesc(TbApply::getGpaSum);
        List<TbApply> tbApplies = this.baseMapper.selectList(queryWrapper);
        return packageOrder(tbApplies);
    }

    private List<OrderResponse> packageOrder(List<TbApply> tbApplies) {
        return tbApplies.stream().map(item->{
            OrderResponse response = new OrderResponse();

            Long stuId = item.getStuId();
            TbStudent student = studentService.getById(stuId);
            if(Objects.isNull(student))throw new ApiException("该学生不存在!");

            response.setStuId(stuId);
            response.setStuName(student.getName());
            response.setJobNumber(String.valueOf(student.getJobNumber()));

            response.setGpaSum(item.getGpaSum());

            Long classId = student.getClassId();
            TbClass tbClass = classService.getById(classId);
            if(Objects.isNull(tbClass))throw new ApiException("该班级不存在!");

            response.setClassDescription(tbClass.getDescription());
            response.setYear(item.getYear());
            return response;
        }).collect(Collectors.toList());

    }

    private List<Long> getStuList(Long resultId){
        List<Long> classIds = itemService.packageResultByResultId(resultId);
        return studentService.getStudentIdsByClassIds(classIds);
    }
}
